#include <rte_mbuf_core.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include "clib_dpdk_packet.h"

typedef struct rte_mbuf  rte_mbuf_t;

#define PACK_MTU                1460

#define IP_HDR_TTL              128

static i32_t
dpdk_pkt_malloc(void* args, void** pkt);

static i32_t
dpdk_pkt_free(void* args, void* pkt);

netif_opt_t dpdk_pkt_opt = {
    .netif_pkt_malloc = dpdk_pkt_malloc,
    .netif_pkt_free   = dpdk_pkt_free
};

static inline i32_t
tcp_dpdk_generate_packet(stack_netif_t *netif, clib_sock_t *sock, u08_t flag, i32_t type)
{
    u16_t      data_len;
    u16_t      send_len;
    u16_t      pack_len;
    u16_t      opts_len = 0;
    eth_hdr_t  *eth;
    ip4_hdr_t  *ip4;
    ip6_hdr_t  *ip6;
    tcp_hdr_t  *tcp;
    u08_t      *data;
    
    rte_mbuf_t *m[32];
    rte_mbuf_t *mbuf;
    i32_t      pkts = 0;
    tcp_stream_t *stream = &sock->tcp_stream;

    /** TODO 组包逻辑外置 逻辑重组 **/

    do {
        mbuf = NULL;

        if(clib_netif_packet_malloc(netif,&mbuf) < 0) {
            return rn_error;
        }
        eth = (eth_hdr_t*)rte_pktmbuf_append(mbuf,sizeof(eth_hdr_t));
        
        clib_ether_hdr_set(eth, ETH_P_IP, &sock->r_mac, &sock->l_mac);

        if(sock->ipv4) {
            ip4 = (ip4_hdr_t*)rte_pktmbuf_append(mbuf,sizeof(ip4_hdr_t));
            
            /** TODO IPV4  **/
            ip4->ihl = IP4_HDR_LEN >> 2;
            ip4->version = 4;
            ip4->tos = 0;
            ip4->tot_len = htons(IP4_HDR_LEN + send_len);
            ip4->id = htons(sock->ip_id++);
            ip4->frag_off = htons(0x4000);	// no fragmentation
            ip4->ttl = IP_HDR_TTL;
            ip4->protocol = IPPROTO_TCP;
            ip4->saddr = sock->ipv4_tuple.l_addr;
            ip4->daddr = sock->ipv4_tuple.r_addr;
            ip4->check = 0;

        } else {
            /** TODO IPV6 **/
        }

        tcp = (tcp_hdr_t*)rte_pktmbuf_append(mbuf,sizeof(tcp_hdr_t));
    
        /** TODO tcp状态判断 三次握手和四次挥手ack和seq判断 **/
        /** TODO tcp数据包组装 **/
        tcp->th_sport = sock->ipv4_tuple.l_port;
        tcp->th_dport = sock->ipv4_tuple.r_port;
        tcp->th_flags = flag;
        tcp->th_ack   = htonl(stream->rcv_nxt);
        tcp->th_seq   = htonl(stream->snd_nxt);
        /** TODO 处理窗口缩放 **/
        tcp->th_win   = htons(stream->rcv_wnd);
        /** TODO 处理SYN选项 **/
        tcp->th_ack   = 0;
        tcp->th_off   = htons(sizeof(tcp_hdr_t) + opts_len);
        tcp->th_sum   = 0;
        tcp->th_urp   = 0;

        /** TODO 添加TCP选项配置 **/

        if(type == send_data_all) {
            /** TODO wack **/
            send_len = PACK_MTU - opts_len;

            data = ((u08_t*)tcp) + (opts_len + sizeof(tcp_hdr_t));
            clib_tcp_buffer_send_get_data(stream->send_buffer,stream->snd_nxt, data, &send_len);
            rte_pktmbuf_append(mbuf, send_len);
            //data = (u08_t*)rte_pktmbuf_append(mbuf, send_len);
            stream->snd_nxt += send_len;

            data_len = stream->send_buffer->ready_len;
        } else {
            data_len = 0;
        }

        if(sock->ipv4) {
            ip4->tot_len = htons(IP4_HDR_LEN + TCP_HDR_LEN + send_len + opts_len);
        } else {

        }
        /** TODO ipv4 tcp check sum **/
        
        m[pkts++] = mbuf;

    } while (data_len > 0);

    clib_netif_packet_put(netif, (void**)m, pkts, CLIB_PKT_DIR_SEND);

    return pkts;
}

static i32_t
dpdk_pkt_malloc(void* args, void** pkt)
{
    return rte_mempool_get((struct rte_mempool*)args,pkt);
}

static i32_t
dpdk_pkt_free(void* args, void* pkt)
{
    (void)args;
    rte_pktmbuf_free(pkt);
}
